﻿using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;

namespace EBA.Dynamic
{
    /// <summary>
    /// 方法编译信息
    /// </summary>
    class MethodEmitData
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="method"></param>
        public MethodEmitData(Type targetType, MethodInfo method)
        {
            this.TargetType = targetType;
            this.Prefix = targetType.Name;

            this.Method = method;
            this.Parameters = method.GetParameters();
            this.ParameterTypes = this.Parameters.Select(i => i.ParameterType).ToArray();

            var typeArguments = new List<Type>();
            typeArguments.Add(typeof(CallSite));
            typeArguments.Add(typeof(object));
            typeArguments.AddRange(this.ParameterTypes);

            if (method.ReturnType == typeof(void))
            {
                this.CallSiteGenericElementType = Expression.GetActionType(typeArguments.ToArray());
                this.CSharpBinderFlags = Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags.ResultDiscarded;
            }
            else
            {
                typeArguments.Add(typeof(object));
                this.CallSiteGenericElementType = Expression.GetFuncType(typeArguments.ToArray()); //typeof(Func<>).MakeGenericType(typeArguments.ToArray());
            }

            this.CSharpArgumentInfos = new List<KeyValuePair<CSharpArgumentInfoFlags, string>>();
            this.CSharpArgumentInfos.Add(new KeyValuePair<CSharpArgumentInfoFlags, string>(CSharpArgumentInfoFlags.None, null));//for CallSite
            this.CSharpArgumentInfos.Add(new KeyValuePair<CSharpArgumentInfoFlags, string>(CSharpArgumentInfoFlags.None, null)); //for this.ContextObject

            foreach (var i in method.GetParameters())
            {
                if (i.IsOut)
                {
                    this.CSharpArgumentInfos.Add(new KeyValuePair<CSharpArgumentInfoFlags, string>(CSharpArgumentInfoFlags.IsOut, null));
                }
                else
                {
                    if (i.ParameterType.IsByRef)
                    {
                        this.CSharpArgumentInfos.Add(new KeyValuePair<CSharpArgumentInfoFlags, string>(CSharpArgumentInfoFlags.IsRef, null));
                    }
                    else
                    {
                        this.CSharpArgumentInfos.Add(new KeyValuePair<CSharpArgumentInfoFlags, string>(CSharpArgumentInfoFlags.None, null));
                    }
                }
            }
        }

        /// <summary>
        /// 类型显示实现前缀
        /// </summary>
        public string Prefix { get; private set; }

        /// <summary>
        /// 方法所在类型信息
        /// </summary>
        public Type TargetType { get; private set; }

        /// <summary>
        /// 目标方法信息
        /// </summary>
        public MethodInfo Method { get; set; }
        /// <summary>
        /// 动态调用类型
        /// </summary>
        public Type CallSiteGenericElementType { get; set; }
        /// <summary>
        /// 方法操作绑定类型
        /// </summary>
        public CSharpBinderFlags CSharpBinderFlags { get; set; }
        /// <summary>
        /// 参数信息
        /// </summary>
        public ParameterInfo[] Parameters { get; set; }
        /// <summary>
        /// 参数类型集合
        /// </summary>
        public Type[] ParameterTypes { get; set; }
        /// <summary>
        /// 参数对应绑定信息
        /// </summary>
        public List<KeyValuePair<CSharpArgumentInfoFlags, string>> CSharpArgumentInfos { get; set; }

    }

}
